/*
 * Copyright 2007-2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 * 
 * Project: JGentleFramework
 */
package org.jgentleframework.reflection.metadata;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;

import org.aopalliance.reflect.Metadata;
import org.jgentleframework.reflection.IAnnotationVisitor;

/**
 * Represents information and behaviours of <code>definition</code>. This
 * information shall be used conjointly with the <code>bean instances</code> to
 * provide configuration information for them in order to be executed or
 * instantiated. Moreover, <code>definition</code> could be used to embed in
 * {@link Method} or {@link Field} so as to provide adscititious information for
 * them. Key of <code>definition</code> is an object that is interpreted of
 * <code>(Class, Method, Field, Annotation, ...)</code> and its value is an
 * corresponding {@link AnnotationMetadata} object that is generated by
 * <code>container</code>.
 * <p>
 * Moreover, it is extended from {@link AnnotatedElement} interface so it
 * provides totally the same behaviors as the {@link Annotation}.
 * 
 * @author LE QUOC CHUNG - mailto: <a
 *         href="mailto:skydunkpro@yahoo.com">skydunkpro@yahoo.com</a>
 * @date Sep 2, 2007
 * @see Metadata
 * @see AnnotatedElement
 */
public interface Definition extends DefinitionCore, Metadata, AnnotatedElement,
		Serializable {
	/**
	 * Returns the owner class of this {@link Definition}. In case of current
	 * {@link Definition} is interpreted of {@link Constructor Constructors},
	 * {@link Method Methods} or {@link Field Fields}, the returned object class
	 * will be the declaring class of them.
	 */
	public Class<?> getOwnerClass();

	/**
	 * Returns a {@link Set set} containing all {@link Field} objects
	 * representing all the fields that are annotated with any annotation.
	 * 
	 * @return Returns an array containing {@link Field} objects if they exist,
	 *         otherwise returns <b>null</b>.
	 */
	public Set<Field> getAllAnnotatedFields();

	/**
	 * Returns a {@link Set set} containing {@link Method} objects representing
	 * all the methods that are annotated with any annotation.
	 * 
	 * @return Returns a {@link Set set} containing all {@link Method} objects
	 *         if they exist, otherwise returns <b>null</b>.
	 */
	public Set<Method> getAllAnnotatedMethods();

	/**
	 * Returns a {@link Set set} containing all {@link Constructor} objects
	 * representing all the constructors that are annotated with any annotation.
	 */
	public Set<Constructor<?>> getAllAnnotatedConstructors();

	/**
	 * Returns a {@link List list} containing {@link Method} objects
	 * representing all the methods that have at least one parameter annotated
	 * with any annotation.
	 * <p>
	 * <b>Note:</b> in case of non-object-class Definition (Definition is
	 * interpreted of {@link Method} or {@link Field} or {@link Constructor},
	 * and is <i>not</i> interpreted of object class), the returned value is
	 * <b>null</b>.
	 * 
	 * @return Returns a {@link List list} containing {@link Method} objects if
	 *         they exist, otherwise returns <b>null</b>.
	 */
	public List<Method> getAllMethodsAnnotatedParameter();

	/**
	 * Returns a {@link List list} containing all {@link Constructor} objects
	 * representing all the methods that have at least one parameter annotated
	 * with any annotation.
	 * <p>
	 * <b>Note:</b> in case of non-object-class Definition (Definition is
	 * interpreted of {@link Method} or {@link Field} or {@link Constructor},
	 * and is <i>not</i> interpreted of object class), the returned value is
	 * <b>null</b>.
	 * 
	 * @return Returns a {@link List list} containing all {@link Constructor}
	 *         objects if they exist, otherwise returns <b>null</b>.
	 */
	public List<Constructor<?>> getAllConstructorsAnnotatedParameter();

	/**
	 * Returns an array containing all member definitions of current
	 * {@link Definition} corresponding to parameters of given method.
	 * <p>
	 * <b>Note:</b> in case of non-object-class Definition (Definition is
	 * interpreted of {@link Method} or {@link Field}, and is <i>not</i>
	 * interpreted of object class), the returned value is <b>null</b>.
	 * 
	 * @param method
	 *            given <code>method</code> corresponds to current definition.
	 * @return returns an array containing definitions if they exist, otherwise
	 *         returns an empty array.
	 */
	public Definition[] getArgsMemberDefinitions(Method method);

	/**
	 * Returns all {@link Field} objects are annotated with given annotation.
	 * <p>
	 * <b>Note:</b> this <code>method</code> always returns <b>null</b> in case
	 * current {@link Definition} is <b><i>not</i></b> interpreted of object
	 * class. This means that if returned value of
	 * {@link DefinitionCore#isInterpretedOfClass()} method is <b>false</b>,
	 * returned value of this method will also be <b>null</b>.
	 * 
	 * @param annotationClass
	 *            the object class of given annotation.
	 * @return returns a {@link List list} containing all {@link Field} objects
	 *         are annotated with given annotation if they exist, <b>null</b>
	 *         otherwise.
	 */
	public List<Field> getFieldsAnnotatedWith(
			Class<? extends Annotation> annotationClass);

	/**
	 * Returns all {@link Field} objects are annotated with given annotations.
	 * <p>
	 * <b>Note:</b> this <code>method</code> always returns <b>null</b> in case
	 * current {@link Definition} is <b><i>not</i></b> interpreted of object
	 * class. This means that if returned value of
	 * {@link DefinitionCore#isInterpretedOfClass()} method is <b>false</b>,
	 * returned value of this method will also be <b>null</b>.
	 * 
	 * @param annotationClasses
	 *            the object classes corresponding to given annotations.
	 * @return returns a {@link List list} containing all {@link Field} objects
	 *         are annotated with given coressponding annotations if they exist,
	 *         <b>null</b> otherwise.
	 */
	public List<Field> getFieldsAnnotatedWith(
			Class<? extends Annotation>... annotationClasses);

	/**
	 * Returns all {@link Constructor constructor} objects are annotated with
	 * given annotation.
	 * <p>
	 * <b>Note:</b> this <code>method</code> always returns <b>null</b> in case
	 * current {@link Definition} is <b><i>not</i></b> interpreted of object
	 * class. This means that if returned value of
	 * {@link DefinitionCore#isInterpretedOfClass()} method is <b>false</b>,
	 * returned value of this method will also be <b>null</b>.
	 * 
	 * @param annotationClass
	 *            the object class of given annotation.
	 * @return returns a {@link List list} containing all {@link Constructor}
	 *         objects are annotated with given annotation if they exist,
	 *         <b>null</b> otherwise.
	 */
	public List<Constructor<?>> getConstructorsAnnotatedWith(
			Class<? extends Annotation> annotationClass);

	/**
	 * Returns all {@link Constructor} objects are annotated with given
	 * corresponding annotations.
	 * <p>
	 * <b>Note:</b> this <code>method</code> always returns <b>null</b> in case
	 * current {@link Definition} is <b><i>not</i></b> interpreted of object
	 * class. This means that if returned value of
	 * {@link DefinitionCore#isInterpretedOfClass()} method is <b>false</b>,
	 * returned value of this method will also be <b>null</b>.
	 * 
	 * @param annotationClasses
	 *            the object classes corresponding to given annotations.
	 * @return returns a {@link List list} containing all {@link Constructor}
	 *         objects are annotated with given coressponding annotations if
	 *         they exist, <b>null</b> otherwise.
	 */
	public List<Constructor<?>> getConstructorsAnnotatedWith(
			Class<? extends Annotation>... annotationClasses);

	/**
	 * In case current definition is interpreted of object class in which given
	 * {@link Field} is declared, returns the corresponding member
	 * {@link Definition} of this {@link Field}.
	 * <p>
	 * <b>Note:</b> this method is only performed if current {@link Definition}
	 * is interpreted of object class.
	 * 
	 * @param field
	 *            the given {@link Field}
	 * @return returns a {@link Definition} if it exists, otherwise returns
	 *         <b>null</b>.
	 */
	public Definition getMemberDefinition(Field field);

	/**
	 * In case current definition is interpreted of object class in which given
	 * {@link Method} is declared, returns the corresponding member
	 * {@link Definition} of this {@link Method}.
	 * <p>
	 * <b>Note:</b> this method is only performed if current {@link Definition}
	 * is interpreted of object class.
	 * 
	 * @param method
	 *            the desired {@link Method}
	 * @return returns a {@link Definition} if it exists, otherwise returns
	 *         <b>null</b>.
	 */
	public Definition getMemberDefinition(Method method);

	/**
	 * In case current {@link Definition} is interpreted of object class in
	 * which given {@link Constructor} is declared, returns the corresponding
	 * member {@link Definition} of this {@link Constructor}.
	 * <p>
	 * <b>Note:</b> this method is only performed if current {@link Definition}
	 * is interpreted of object class.
	 * 
	 * @param constructor
	 *            the desired {@link Constructor}
	 * @return returns a {@link Definition} if it exists, otherwise returns
	 *         <b>null</b>.
	 */
	public Definition getMemberDefinition(Constructor<?> constructor);

	/**
	 * In case current definition is interpreted of the object class in which
	 * given object is declared, returns the corresponding member
	 * {@link Definition} of this object.
	 * <p>
	 * <b>Note:</b> the given object should be only {@link Field} or
	 * {@link Method} or {@link Constructor}.
	 * 
	 * @param obj
	 *            the desired object.
	 * @return returns a {@link Definition} if it exists, otherwise returns
	 *         <b>null</b>.
	 */
	public Definition getMemberDefinition(Object obj);

	/**
	 * Returns an array containing member {@link Definition definitions}
	 * corresponding to the {@link Field field} according to the given name.
	 * <p>
	 * <b>Note:</b> this method is only performed if current {@link Definition}
	 * is interpreted of object class.
	 * 
	 * @param fieldName
	 *            the name of desired {@link Field fields}
	 * @return returns an array of {@link Definition definitions} if they exist,
	 *         otherwise returns <b>null</b>.
	 */
	public Definition[] getMemberDefinitionOfField(String fieldName);

	/**
	 * Returns an array containing member {@link Definition definitions}
	 * corresponding to the specified {@link Method} according to the given
	 * method name and argument types.
	 * <p>
	 * <b>Note:</b> this method is only performed if current {@link Definition}
	 * is interpreted of object class.
	 * 
	 * @param methodName
	 *            the name of {@link Method}
	 * @param argsTypes
	 *            the specified parameter types of method. Indicates <b>null</b>
	 *            in case desired method doesn't have any parameters.
	 * @return Returns an array containing member {@link Definition definitions}
	 *         if they exists, otherwise returns <b>null</b>.
	 */
	public Definition[] getMemberDefinitionOfMethod(String methodName,
			Class<?>[] argsTypes);

	/**
	 * Returns all method objects are annotated with given annotation.
	 * <p>
	 * <b>Note:</b> this <code>method</code> always returns <b>null</b> in case
	 * current {@link Definition} is <b><i>not</i></b> interpreted of the object
	 * class. This means that if returned value of
	 * {@link DefinitionCore#isInterpretedOfClass()} method is <b>false</b>,
	 * returned value of this method will also be <b>null</b>.
	 * 
	 * @param annotationClass
	 *            the object class of given annotation.
	 * @return returns a {@link List list} containing all {@link Method} objects
	 *         are annotated with given annotation if they exist, <b>null</b>
	 *         otherwise.
	 */
	public List<Method> getMethodsAnnotatedWith(
			Class<? extends Annotation> annotationClass);

	/**
	 * Returns all method objects are annotated with given annotations.
	 * <p>
	 * <b>Note:</b> this <code>method</code> always returns <b>null</b> in case
	 * current {@link Definition} is <b><i>not</i></b> interpreted of the object
	 * class. This means that if returned value of
	 * {@link DefinitionCore#isInterpretedOfClass()} method is <b>false</b>,
	 * returned value of this method will also be <b>null</b>.
	 * 
	 * @param annotationClasses
	 *            the object classes corresponding to given annotations.
	 * @return returns a {@link List list} containing all {@link Method} objects
	 *         are annotated with given corresponding annotations if they exist,
	 *         <b>null</b> otherwise.
	 */
	public List<Method> getMethodsAnnotatedWith(
			Class<? extends Annotation>... annotationClasses);

	/**
	 * Returns <b>true</b> if this {@link Definition} is not an empty
	 * {@link Definition}. It means that there is at least one annotation
	 * annotated in current {@link Definition} (not includes member definition
	 * of its).
	 */
	public boolean isAnnotationPresent();

	/**
	 * Returns an array containing boolean results according to the existential
	 * corresponding {@link Definition definition}.
	 * 
	 * @param classes
	 *            the given array containing classes object corresponding to the
	 *            annotation types
	 * @return an array containing boolean results if there is at least one
	 *         annotation present on this element, if not, returns an empty
	 *         array.
	 */
	public boolean[] isAnnotationPresent(Class<? extends Annotation>... classes);

	/**
	 * Returns <b>true</b> if current {@link Definition} has at least one
	 * {@link Field} annotated with any annotation. Otherwise returns
	 * <b>false</b>.
	 * <p>
	 * <b>Note:</b> this <code>method</code> always returns <b>false</b> in case
	 * current {@link Definition} is <b><i>not</i></b> interpreted of object
	 * class. This means that if returned value of
	 * {@link DefinitionCore#isInterpretedOfClass()} method is <b>false</b>,
	 * returned value of this method will also be <b>false</b>.
	 */
	public boolean isAnnotationPresentOnAnyFields();

	/**
	 * Returns <b>true</b> if given annotation is annotated with at least one
	 * {@link Field} of original object class which current {@link Definition}
	 * is interpreted of. Otherwise returns <b>false</b>.
	 * <p>
	 * <b>Note:</b> this <code>method</code> always returns <b>false</b> in case
	 * current {@link Definition} is <b><i>not</i></b> interpreted of object
	 * class. This means that if returned value of
	 * {@link DefinitionCore#isInterpretedOfClass()} method is <b>false</b>,
	 * returned value of this method will also be <b>false</b>.
	 * 
	 * @param annotationClass
	 *            the object class of given annotation.
	 */
	public boolean isAnnotationPresentOnAnyFields(
			Class<? extends Annotation> annotationClass);

	/**
	 * Returns <b>true</b> if current {@link Definition} has at least one
	 * {@link Method} annotated with any annotation. Otherwise returns
	 * <b>false</b>.
	 * <p>
	 * <b>Note:</b> this <code>method</code> always returns <b>false</b> in case
	 * current {@link Definition} is <b><i>not</i></b> interpreted of one object
	 * class. This means that if returned value of
	 * {@link DefinitionCore#isInterpretedOfClass()} method is <b>false</b>,
	 * returned value of this method will also be <b>false</b>.
	 */
	public boolean isAnnotationPresentOnAnyMethods();

	/**
	 * Returns <b>true</b> if given annotation is annotated with at least one
	 * {@link Method} of original object class which current {@link Definition}
	 * is interpreted of. Otherwise returns <b>false</b>.
	 * <p>
	 * <b>Note:</b> this <code>method</code> always returns <b>false</b> in case
	 * current {@link Definition} is <b><i>not</i></b> interpreted of object
	 * class. This means that if returned value of
	 * {@link DefinitionCore#isInterpretedOfClass()} method is <b>false</b>,
	 * returned value of this method will also be <b>false</b>.
	 * 
	 * @param annotationClass
	 *            the object class of given annotation.
	 */
	public boolean isAnnotationPresentOnAnyMethods(
			Class<? extends Annotation> annotationClass);

	/**
	 * Returns <b>true</b> if current {@link Definition} has at least one
	 * {@link Constructor} annotated with any annotation. Otherwise returns
	 * <b>false</b>.
	 * <p>
	 * <b>Note:</b> this <code>method</code> always returns <b>false</b> in case
	 * current {@link Definition} is <b><i>not</i></b> interpreted of one object
	 * class. This means that if returned value of
	 * {@link DefinitionCore#isInterpretedOfClass()} method is <b>false</b>,
	 * returned value of this method will also be <b>false</b>.
	 */
	public boolean isAnnotationPresentOnAnyConstructors();

	/**
	 * Returns <b>true</b> if given annotation is annotated with at least one
	 * {@link Constructor} of original object class which current
	 * {@link Definition} is interpreted of. Otherwise returns <b>false</b>.
	 * <p>
	 * <b>Note:</b> this <code>method</code> always returns <b>false</b> in case
	 * current {@link Definition} is <b><i>not</i></b> interpreted of object
	 * class. This means that if returned value of
	 * {@link DefinitionCore#isInterpretedOfClass()} method is <b>false</b>,
	 * returned value of this method will also be <b>false</b>.
	 * 
	 * @param annotationClass
	 *            the object class of given annotation.
	 */
	public boolean isAnnotationPresentOnAnyConstructors(
			Class<? extends Annotation> annotationClass);

	/**
	 * Returns <b>true</b> in case current {@link Definition} has at least one
	 * method which also has at least one parameter annotated with <b>any
	 * annotation</b>, otherwise returned value will be <b>false</b>.
	 * <p>
	 * <b>Note:</b> <i>the performance of this method is in the same way in all
	 * case current {@link Definition} is interpreted of object class or
	 * {@link Method} object or {@link Constructor} object.</i>
	 */
	public boolean isAnnotationPresentOnAnyParameters();

	/**
	 * Returns <b>true</b> in case current {@link Definition} has at least one
	 * method which also has at least one parameter annotated with <b>the given
	 * annotation</b>, otherwise returned value will be <b>false</b>.
	 * <p>
	 * <b>Note:</b> <i>the performance of this method is in the same way in all
	 * case current {@link Definition} is interpreted of object class and
	 * {@link Method} object or {@link Constructor} object.</i>
	 * 
	 * @param annotationClass
	 *            the object class of given annotation.
	 */
	public boolean isAnnotationPresentOnAnyParameters(
			Class<? extends Annotation> annotationClass);

	/**
	 * Returns <b>true</b> if there is at least one annotation is annotated at
	 * anywhere in current {@link Definition} (includes all member definition of
	 * it), otherwise returns <b>false</b>.
	 */
	public boolean isAnnotationPresentOnAnyWhere();

	/**
	 * Returns <b>true</b> if given annotation is annotated at anywhere in
	 * current {@link Definition} (includes all member definition of it),
	 * otherwise returns <b>false</b>.
	 * 
	 * @param annotationClass
	 *            the object class of given annotation.
	 */
	public boolean isAnnotationPresentOnAnyWhere(
			Class<? extends Annotation> annotationClass);

	/**
	 * Sets the visitor.
	 * 
	 * @param visitor
	 *            the visitor
	 */
	public void setVisitor(IAnnotationVisitor visitor);
}